package com.xyxy.platform.modules.service.common.sms.impl;

import com.google.common.collect.Lists;
import com.xyxy.platform.modules.core.cache.memcached.SpyMemcachedClient;
import com.xyxy.platform.modules.core.utils.Collections3;
import com.xyxy.platform.modules.service.common.exception.SmsException;
import com.xyxy.platform.modules.service.common.sms.SmsService;
import com.xyxy.platform.modules.service.common.sms.vo.SmsTemplateType;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.text.MessageFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 简介: 短信验证码服务
 *
 * @author Caizhenegda
 * @version 1.0
 * @Date 2015-12-24 14:38
 */
@Service
public class SmsServiceImpl implements SmsService {

    Logger logger = LoggerFactory.getLogger("sms");
    //用户获取验证码的次数
    Integer count = 0;
    /**
     * 模版内容
     */
    private Map<Integer, String> smsContent = new HashMap<>();

    @PostConstruct
    private void init() {
        smsContent.put(SmsTemplateType.REG_MSG.ordinal(), "【星语心愿】验证码为{0}，有效期一分钟。如非本人操作，请忽略此信息。");
        smsContent.put(SmsTemplateType.ZH_MSG.ordinal(), "【星语心愿】验证码为{0}，有效期五分钟。您正在验证手机找回密码，如非本人操作，请忽略此信息。");
        smsContent.put(SmsTemplateType.XGSJ_MSG.ordinal(), "【星语心愿】验证码为{0}，有效期五分钟。您正在更换手机号码，如非本人操作，请忽略此信息。");
        smsContent.put(SmsTemplateType.BDXSJ_MSG.ordinal(), "【星语心愿】验证码为{0}，有效期五分钟。您正在绑定新手机号码，如非本人操作，请忽略此信息。");
        smsContent.put(SmsTemplateType.GRXX_MSG.ordinal(), "【星语心愿】你的个人信息认证已通过，请及时登录网站查看，如有任何疑问请拨打24小时客服热线400-666-6789。");
        smsContent.put(SmsTemplateType.GRXXE_MSG.ordinal(), "【星语心愿】你的个人信息认证未通过，请及时登录网站查看。如有任何疑问请拨打24小时客服热线400-666-6789。");
        smsContent.put(SmsTemplateType.XDCG_MSG.ordinal(), "【星语心愿】您已经下单成功。请及时与服务商1391709262联系，确认服务相关事宜。");
    }

    @Autowired
    private SpyMemcachedClient memcachedClient;

    /**
     * 获取当前时间到凌晨0点的时间差
     *
     * @param today
     * @return
     * @throws ParseException
     */
    public int getTime(Date today) {
        Date date = new Date();
        SimpleDateFormat sf = new SimpleDateFormat("yyyyMMdd");
        String nowDate = sf.format(date);
        //通过日历获取下一天日期
        Calendar cal = Calendar.getInstance();
        try {
            cal.setTime(sf.parse(nowDate));
        } catch (ParseException e) {
            e.printStackTrace();
        }
        cal.add(Calendar.DAY_OF_YEAR, +1);

        Long l = (cal.getTimeInMillis() - date.getTime()) / 1000;
        return l.intValue();
    }

    /**
     * 获得距离当天23:59还有多少秒
     *
     * @return
     */
    public Long getCacheExpiredTime() {
        DateTime now = new DateTime();
        DateTime dateTime = new DateTime(now.getYear(), now.getMonthOfYear(), now.getDayOfMonth(), 23, 59, 0, 0);
        return (dateTime.toDate().getTime() - System.currentTimeMillis()) / 1000;
    }

    @Override
    public void sendRegisterCode(String mobileNumber, String ip) throws SmsException {
        // 一个ip使用手机号限制
        Integer ipMobiles = 3;
        Integer mobileSendCount = 5;
        if (StringUtils.isEmpty(mobileNumber) || StringUtils.isEmpty(ip)) {
            logger.warn("发送注册验证码失败, 手机号或者ip为空!");
            return;
        }
        //ip 使用了几个手机号 判断
        List<String> mobiles = memcachedClient.get(ip + "_reg");
        if (Collections3.isEmpty(mobiles)) mobiles = Lists.newArrayList();
        if (mobiles.size() > ipMobiles) {
            logger.warn("ip: {} 可能存在恶意攻击, 因为使用了多个手机号进行注册!手机号: {}", ip, StringUtils.join(mobiles.toArray(), ","));
            throw new SmsException("存在恶意攻击, 因为使用了多个手机号进行注册!", 1);
        } else {
            if (!mobiles.contains(mobileNumber)) {
                mobiles.add(mobileNumber);
            }
        }
        //手机号发送了几次判断
        Integer sendCount = memcachedClient.get(mobileNumber + "_reg");
        if (null == sendCount) sendCount = 0;
        if (sendCount > mobileSendCount) {
            logger.warn("手机号码注册短信超过了{}次, 不再发送!", mobileSendCount);
            throw new SmsException("手机号码注册短信超过了限制!", 2);
        }

        //验证通过, 开始进行短信发送
        //获取memcached是否存在
        Long code = memcachedClient.get(mobileNumber);
        if (code == null) {
            Random random = new Random();
            code = Long.valueOf(random.nextInt(9000) + 1000);
            String content = generateContent(SmsTemplateType.REG_MSG, code.toString());
            logger.debug("手机号码：{}, 发送内容: {}, 缓存70秒.", mobileNumber, content);
            sendSms(mobileNumber, content);
            //有效期60秒
            memcachedClient.set(mobileNumber, 70, code);
        } else {
            throw new SmsException("手机号码注册短信验证码还在有效期内!", 3);
        }
        memcachedClient.set(mobileNumber + "_reg", getCacheExpiredTime().intValue(), ++sendCount);
        memcachedClient.set(ip + "_reg", getCacheExpiredTime().intValue(), mobiles);
    }

    @Override
    public Long generateSmsCode(String mobileNumber, SmsTemplateType smsTemplateType) {
        //获取memcached是否存在
        Long code = memcachedClient.get(mobileNumber);
        if (memcachedClient.get(mobileNumber + "Count") != null) {
            memcachedClient.set(mobileNumber + "Count", getTime(new Date()), 1);
        }
        if (code == null) {
            count = count + 1;
            Random random = new Random();
            code = Long.valueOf(random.nextInt(9000) + 1000);
            String content = generateContent(smsTemplateType, code.toString());
            logger.debug("手机号码：" + mobileNumber);
            logger.debug("短信内容：" + content);
            sendSms(mobileNumber, content);
            //有效期60秒
            memcachedClient.set(mobileNumber, 70, code);
            memcachedClient.set(mobileNumber + "Count", getTime(new Date()), count);
        }
        logger.debug("生成短信验证码: [{}], 并写入缓存, 70秒内有效!", code);
        return code;
    }

    @Async
    @Override
    public void sendSms(String mobileNumber, String content) {
        String url = "http://112.90.145.10:6666/sms.aspx?action=send&userid=74&account=106904&password=123456";
        url += "&mobile=" + mobileNumber;  //手机号码
        url += "&content=" + content;
        HttpClient httpclient = HttpClients.createDefault();
        List<BasicNameValuePair> list = new ArrayList<BasicNameValuePair>();
        list.add(new BasicNameValuePair("url", url));
        // 创建一个post请求
        HttpPost post = new HttpPost(url);
        // 设置参数以及参数的编码格式
        // 将返回结果转换为String以及设置编码格式
        String result = null;
        try {
            post.setEntity(new UrlEncodedFormEntity(list, "utf-8"));
            // 获取返回结果
            org.apache.http.HttpResponse response = null;
            try {
                response = httpclient.execute(post);
            } catch (IOException e) {
                e.printStackTrace();
            }
            HttpEntity entity = response.getEntity();

            try {
                result = EntityUtils.toString(entity, "utf-8");
            } catch (IOException e) {
                e.printStackTrace();
            }
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        logger.info("短信发送结果 xml 内容: {}.", result);
    }

    /**
     * 判断验证码是否还在有效期内
     * 存在则不能重复发送
     *
     * @param mobileNumber 手机号码
     * @return
     */
    @Override
    public boolean exist(String mobileNumber) {
        boolean flag = null == memcachedClient.<Long>get(mobileNumber);
        return !flag;
    }

    /**
     * 判断验证码是否正确
     *
     * @param mobileNumber 手机号码
     * @param code         输入的验证码
     * @return
     */
    @Override
    public boolean verifyCode(String mobileNumber, Long code) {
        //从缓存中获得生成的验证码
        Long _code = memcachedClient.<Long>get(mobileNumber);
        if (null != _code && _code.longValue() == code.longValue()) {
            return true;
        }
        return false;
    }

    @Override
    public String generateContent(SmsTemplateType smsTemplateType, Object... arguments) {
        String tmpContent = smsContent.get(smsTemplateType.ordinal());
        return MessageFormat.format(tmpContent, arguments);
    }

}
